/**
 @file sys_usw_flexe.c

 @author  Copyright (C) 2011 Centec Networks Inc.  All rights reserved.

 @date 2011-11-22

 @version v2.0

*/

/****************************************************************************
 *
* Header Files
*
****************************************************************************/
#include "sal.h"
#include "ctc_error.h"
#include "ctc_debug.h"
#include "ctc_interrupt.h"
#include "ctc_warmboot.h"
#include "sys_usw_register.h"
#include "sys_usw_mchip.h"
#include "sys_usw_mac.h"
#include "sys_usw_flexe.h"
#include "sys_usw_interrupt.h"
#include "sys_usw_wb_common.h"

/****************************************************************************
 *
* Defines and Macros
*
*****************************************************************************/

/****************************************************************************
 *
* Global and Declaration
*
*****************************************************************************/

/****************************************************************************
 *
* Function
*
*****************************************************************************/
sys_flexe_master_t* p_usw_flexe_master[CTC_MAX_LOCAL_CHIP_NUM_PP] = {NULL};
#define FLEXE_DBG_PRINTF(FMT, ...)

#if defined(_SAL_LINUX_KM)
#define FLEXE_DUMP(FMT, ...)   
#else
#define FLEXE_DUMP(FMT, ...)   
#endif

#define SYS_WB_APPID(lchip, modid, subid)   (((lchip)<<16) | CTC_WB_APPID(modid, subid))

/* No lock */
int32
sys_usw_flexe_update_misc(uint8 lchip)
{
    int32 ret = 0;
    if(MCHIP_FLEXE(lchip)->flexe_update_misc)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_update_misc(lchip);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }

    return ret;
}

void
sys_usw_flexe_alarm_thread(void *para)
{
    uint8  lchip       = (uintptr)para;
    uint8  gchip       = 0;

    (void)sys_usw_get_gchip_id(lchip, &gchip);
    SYS_LCHIP_CHECK_ACTIVE_START_THREAD(lchip);

    while(1)
    {   
        SYS_LCHIP_CHECK_ACTIVE_IN_THREAD(lchip);
        SYS_CHIP_CHECK_RESET_HW_IN_THREAD(lchip);
        if(p_usw_flexe_master[lchip]->polling_status == 0)
        {
            continue;
        }
        if (MCHIP_FLEXE(lchip)->flexe_monitor_alarm)
        {
            MCHIP_FLEXE(lchip)->flexe_monitor_alarm(lchip);
        }
        sys_usw_flexe_update_misc(lchip);
        sal_task_sleep(1000);
    }
}

void
sys_usw_flexe_monitor_thread(void *para)
{
    uint8  lchip       = (uintptr)para;
    uint8  gchip       = 0;

    (void)sys_usw_get_gchip_id(lchip, &gchip);
    SYS_LCHIP_CHECK_ACTIVE_START_THREAD(lchip);

    while(1)
    {        
        SYS_LCHIP_CHECK_ACTIVE_IN_THREAD(lchip);
        SYS_CHIP_CHECK_RESET_HW_IN_THREAD(lchip);
        if(p_usw_flexe_master[lchip]->polling_status == 0)
        {
            continue;
        }
        if (MCHIP_FLEXE(lchip)->flexe_monitor)
        {
            MCHIP_FLEXE(lchip)->flexe_monitor(lchip);
        }
        sal_task_sleep(100);
    }
}

void
_sys_tmm_flexe_cr_timer_thread(void* para)
{
    uint8 lchip            = (uintptr)para;
    uint8 gchip            = 0;

    (void)sys_usw_get_gchip_id(lchip, &gchip);
    SYS_LCHIP_CHECK_ACTIVE_START_THREAD(lchip);

    while(1)
    {        
        SYS_LCHIP_CHECK_ACTIVE_IN_THREAD(lchip);
        SYS_CHIP_CHECK_RESET_HW_IN_THREAD(lchip);
        if(p_usw_flexe_master[lchip]->polling_status == 0)
        {
            continue;
        }
        MAC_LOCK;
        if (MCHIP_FLEXE(lchip)->flexe_monitor_cr_timer)
        {
            MCHIP_FLEXE(lchip)->flexe_monitor_cr_timer(lchip);
        }
        MAC_UNLOCK;
        sal_task_sleep(SYS_FLEXE_CR_TIMER_POLLING_CLK);
    }
}

int32
sys_usw_flexe_monitor_status(uint8 lchip)
{
    drv_work_platform_type_t platform_type;
    int32 ret = 0;
    uintptr chip_id = lchip;
    uint64 cpu_mask = 0;

    if (sys_usw_chip_get_reset_hw_en(lchip))
    {
        return CTC_E_NONE;
    }
    CTC_ERROR_RETURN(drv_get_platform_type(lchip, &platform_type));
    if (platform_type != HW_PLATFORM)
    {
        return CTC_E_NONE;
    }

    cpu_mask = sys_usw_chip_get_affinity(lchip, 0);
    ret = sys_usw_task_create(lchip, &(p_usw_flexe_master[lchip]->p_monitor_scan), "ctcFlexeMon",
                          SAL_DEF_TASK_STACK_SIZE, SAL_TASK_PRIO_DEF, SAL_TASK_TYPE_LINK_SCAN, cpu_mask, sys_usw_flexe_monitor_thread, (void*)chip_id);
    if (ret < 0)
    {
        SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " %% Feature not initialized \n");
        return CTC_E_NOT_INIT;
    }

    ret = sys_usw_task_create(lchip, &(p_usw_flexe_master[lchip]->cr_timer_scan.monitor_task), "ctcFlexeTimer",
                          SAL_DEF_TASK_STACK_SIZE, SAL_TASK_PRIO_DEF, SAL_TASK_TYPE_OTHERS, cpu_mask, _sys_tmm_flexe_cr_timer_thread, (void*)chip_id);              
    if (ret < 0)
    {
        SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " %% Feature not initialized \n");
        return CTC_E_NOT_INIT;
    }

    ret = sys_usw_task_create(lchip, &(p_usw_flexe_master[lchip]->p_monitor_alarm_scan), "ctcFlexeMonAlarm",
                          SAL_DEF_TASK_STACK_SIZE, SAL_TASK_PRIO_DEF, SAL_TASK_TYPE_LINK_SCAN, cpu_mask, sys_usw_flexe_alarm_thread, (void*)chip_id);
    if (ret < 0)
    {
        SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " %% Feature not initialized \n");
        return CTC_E_NOT_INIT;
    }

    p_usw_flexe_master[lchip]->polling_status = 1;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_MASTER, 1);

    return CTC_E_NONE;
}

int32
sys_usw_flexe_event_isr(uint8 lchip, uint32 intr, void* p_data)
{
    int32 ret = 0;
    
    if (MCHIP_FLEXE(lchip)->flexe_event_isr)
    {
       ret = MCHIP_FLEXE(lchip)->flexe_event_isr(lchip, intr, p_data);
    }

    return ret;
}

int32
sys_usw_flexe_dump_db(uint8 lchip, sal_file_t dump_db_fp,ctc_global_dump_db_t* p_dump_param)
{
    uint32 i  = 0;
    uint32 j  = 0;
    int32 ret = CTC_E_NONE;
    sys_flexe_group_t* p_group_node                  = NULL;
    sys_flexe_client_t* p_client_node                = NULL;
    ctc_slistnode_t* node                            = NULL;

    SYS_FLEXE_INIT_CHECK();
    MAC_LOCK;

    SYS_DUMP_DB_LOG(dump_db_fp, "\n");
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "# FlexE");
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "{");
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "Master config:");
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "----------------------------------------------------------------------------------------------------------------------");
    SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","polling_status", p_usw_flexe_master[lchip]->polling_status);
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "----------------------------------------------------------------------------------------------------------------------");

    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "Group node:");
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "----------------------------------------------------------------------------------------------------------------------");
    CTC_SLIST_LOOP(p_usw_flexe_master[lchip]->group_list, node)
    {
        p_group_node = _ctc_container_of(node, sys_flexe_group_t, head);

        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","group_id",      p_group_node->group_id);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","group_number",  p_group_node->group_number);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","switch_mode",   p_group_node->switch_mode);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","rx_cfg_mode",   p_group_node->rx_cfg_mode);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","flexe_shim_id", p_group_node->flexe_shim_id);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","inst_cnt",      p_group_node->inst_cnt);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","phy_cnt",       p_group_node->phy_cnt);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","event_bmp",     p_group_node->event_bmp);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","cr_timer",      p_group_node->cr_timer);
        if (0 == p_group_node->phy_cnt)
        {
            continue;
        }
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:",  "inst_list");
        for (i = 0; i < p_group_node->inst_cnt; i ++)
        {
            SYS_DUMP_DB_LOG(dump_db_fp, "%u ",p_group_node->inst_list[i]);
        }
        SYS_DUMP_DB_LOG(dump_db_fp, "\n");

        SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "---------------------------------------------------------------");
        SYS_DUMP_DB_LOG(dump_db_fp, "%-12s | %s\n", "phy_list", "phy_number logical_serdes_base inst_base pcs_mode fec_type crc_cnt event_bmp");
        for (i = 0; i < p_group_node->phy_cnt; i ++)
        {          
            SYS_DUMP_DB_LOG(dump_db_fp, "%-12d | %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",\
                          i, p_group_node->phy_list[i].phy_number,\
                          p_group_node->phy_list[i].logical_serdes_base,\
                          p_group_node->phy_list[i].inst_base,\
                          p_group_node->phy_list[i].pcs_mode,\
                          p_group_node->phy_list[i].fec_type,\
                          p_group_node->phy_list[i].crc_cnt,\
                          p_group_node->phy_list[i].event_bmp);
        }

        SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "---------------------------------------------------------------");
        SYS_DUMP_DB_LOG(dump_db_fp, "%-12s | %s\n", "tx.dir_inst", "flush_bmp crcac_intr_bmp cr_flip ca_flip c_flip");
        for (i = 0; i < p_group_node->inst_cnt; i ++)
        {
            SYS_DUMP_DB_LOG(dump_db_fp, "%-12d | %-10u %-10u %-10u %-10u %-10u\n",\
              i, p_group_node->tx.dir_inst[i].flush_bmp,\
              p_group_node->tx.dir_inst[i].crcac_intr_bmp,\
              p_group_node->tx.dir_inst[i].cr_flip,\
              p_group_node->tx.dir_inst[i].ca_flip,\
              p_group_node->tx.dir_inst[i].c_flip);
        }

        SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "---------------------------------------------------------------");
        SYS_DUMP_DB_LOG(dump_db_fp, "%-12s | %s\n", "rx.dir_inst", "flush_bmp crcac_intr_bmp cr_flip ca_flip c_flip");
        for (i = 0; i < p_group_node->inst_cnt; i ++)
        {
            SYS_DUMP_DB_LOG(dump_db_fp, "%-12d | %-10u %-10u %-10u %-10u %-10u\n",\
              i, p_group_node->rx.dir_inst[i].flush_bmp,\
              p_group_node->rx.dir_inst[i].crcac_intr_bmp,\
              p_group_node->rx.dir_inst[i].cr_flip,\
              p_group_node->rx.dir_inst[i].ca_flip,\
              p_group_node->rx.dir_inst[i].c_flip);
        }

        SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "---------------------------------------------------------------");
        SYS_DUMP_DB_LOG(dump_db_fp, "%-12s | %s\n", "tx.cc","cycle_value shim_chid inst(slot_cnt, cc_subcalmask)...... ");
        for (i = 0; i < MCHIP_CAP(SYS_CAP_FLEXE_MAX_CYCLE); i ++)
        {
            SYS_DUMP_DB_LOG(dump_db_fp, "%-12d | %-10u %-10u ",i, p_group_node->tx.cc[i].cycle_value, p_group_node->tx.cc[i].shim_chid);
            for (j = 0; j < MCHIP_CAP(SYS_CAP_FLEXE_MAX_INST_CNT); j ++)
            {

                if (NULL != p_group_node->tx.cc[i].inst)
                {
                    SYS_DUMP_DB_LOG(dump_db_fp, "(%-u, %u) ",p_group_node->tx.cc[i].inst[j].slot_cnt, p_group_node->tx.cc[i].inst[j].cc_subcalmask);
                }
                else
                {
                    SYS_DUMP_DB_LOG(dump_db_fp, "(-, -) ");
                }

            }
            SYS_DUMP_DB_LOG(dump_db_fp, "\n");
        }

        SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "---------------------------------------------------------------");
        SYS_DUMP_DB_LOG(dump_db_fp, "%-12s | %s\n", "rx.cc", "cycle_value shim_chid inst(slot_cnt, cc_subcalmask)...... ");
        for (i = 0; i < MCHIP_CAP(SYS_CAP_FLEXE_MAX_CYCLE); i ++)
        {
            SYS_DUMP_DB_LOG(dump_db_fp, "%-12d | %-10u %-10u ",i, p_group_node->rx.cc[i].cycle_value, p_group_node->rx.cc[i].shim_chid);
            for (j = 0; j < MCHIP_CAP(SYS_CAP_FLEXE_MAX_INST_CNT); j ++)
            {
                if (NULL != p_group_node->rx.cc[i].inst)
                {
                   SYS_DUMP_DB_LOG(dump_db_fp, "(%u, %u) ",p_group_node->rx.cc[i].inst[j].slot_cnt, p_group_node->rx.cc[i].inst[j].cc_subcalmask); 
                }
                else
                {
                   SYS_DUMP_DB_LOG(dump_db_fp, "(-, -) ");
                }
            }
            SYS_DUMP_DB_LOG(dump_db_fp, "\n");
        }
        SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "----------------------------------------------------------------------------------------------------------------------");
    }
    
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "Client node:");
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "----------------------------------------------------------------------------------------------------------------------");
    CTC_SLIST_LOOP(p_usw_flexe_master[lchip]->client_list, node)
    {
        p_client_node = _ctc_container_of(node, sys_flexe_client_t, head);

        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","client_id",       p_client_node->client_id);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","client_number",   p_client_node->client_number);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","group_id",        p_client_node->group_id);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","flexe_shim_id",   p_client_node->flexe_shim_id);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","shim_chid",       p_client_node->shim_chid);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","tx_xc_chid",      p_client_node->tx_xc_chid);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","rx_xc_chid",      p_client_node->rx_xc_chid);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","cross_client_id", p_client_node->cross_client_id);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","gport",           p_client_node->gport);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","mac_id",          p_client_node->mac_id);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","chan_id",         p_client_node->chan_id);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","cross_enable",    p_client_node->cross_enable);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","aps_role",        p_client_node->aps_role);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","bind_oam",        p_client_node->bind_oam);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","flow_type",       p_client_node->flow_type);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","tx.op",           p_client_node->tx.op);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","tx.read_ptr",     p_client_node->tx.read_ptr);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","rx.op",           p_client_node->rx.op);
        SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n","rx.read_ptr",     p_client_node->rx.read_ptr);
    }
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "----------------------------------------------------------------------------------------------------------------------");
    
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "}");
    MAC_UNLOCK;

    return ret;
}


#define  __FLEXE_WB__
STATIC int32
_sys_usw_flexe_wb_group_lookup(uint8 lchip, uint32 group_id, sys_flexe_group_t** pp_group)
{
    sys_flexe_group_t* p_group = NULL;
    ctc_slistnode_t* node = NULL;

    CTC_SLIST_LOOP(p_usw_flexe_master[lchip]->group_list, node)
    {
        p_group = _ctc_container_of(node, sys_flexe_group_t, head);
        if (p_group->group_id == group_id)
        {
            *pp_group = p_group;
            break;
        }
    }

    return CTC_E_NONE;
}

int32
_sys_usw_flexe_wb_master_mapping(uint8 lchip, sys_wb_flexe_master_t* p_wb_master, uint8 sync)
{
    if (sync)
    {
        p_wb_master->polling_status = p_usw_flexe_master[lchip]->polling_status;
    }
    else
    {
        p_usw_flexe_master[lchip]->polling_status = p_wb_master->polling_status;
    }

    return CTC_E_NONE;
}

int32
_sys_usw_flexe_wb_group_mapping(uint8 lchip, sys_wb_flexe_group_t* p_wb_group, sys_flexe_group_t* p_group_node, uint8 sync)
{    
    if (sync)
    {
        p_wb_group->group_id      = p_group_node->group_id;
        p_wb_group->group_number  = p_group_node->group_number;
        p_wb_group->switch_mode   = p_group_node->switch_mode;
        p_wb_group->rx_cfg_mode   = p_group_node->rx_cfg_mode;
        p_wb_group->flexe_shim_id = p_group_node->flexe_shim_id;
        p_wb_group->inst_cnt      = p_group_node->inst_cnt;
        p_wb_group->phy_cnt       = p_group_node->phy_cnt;
        p_wb_group->pad_en        = p_group_node->pad_en;
        p_wb_group->event_bmp     = p_group_node->event_bmp;
        p_wb_group->phy_list      = NULL;
        p_wb_group->inst_list     = NULL;
        p_wb_group->cr_timer      = p_group_node->cr_timer;
        
        p_wb_group->tx.active     = p_group_node->tx.active;
        p_wb_group->tx.crac_state = p_group_node->tx.crac_state;
        p_wb_group->tx.dir_inst   = NULL;
        
        p_wb_group->rx.active     = p_group_node->rx.active;
        p_wb_group->rx.crac_state = p_group_node->rx.crac_state;
        p_wb_group->rx.dir_inst   = NULL;
    }
    else
    {
        p_group_node->group_id      = p_wb_group->group_id;
        p_group_node->group_number  = p_wb_group->group_number;
        p_group_node->switch_mode   = p_wb_group->switch_mode;
        p_group_node->rx_cfg_mode   = p_wb_group->rx_cfg_mode;
        p_group_node->flexe_shim_id = p_wb_group->flexe_shim_id;
        p_group_node->inst_cnt      = p_wb_group->inst_cnt;
        p_group_node->phy_cnt       = p_wb_group->phy_cnt;
        p_group_node->pad_en        = p_wb_group->pad_en;
        p_group_node->event_bmp     = p_wb_group->event_bmp;
        p_group_node->phy_list      = NULL;
        p_group_node->inst_list     = NULL;
        p_group_node->cr_timer      = p_wb_group->cr_timer;

        p_group_node->tx.active     = p_wb_group->tx.active;
        p_group_node->tx.crac_state = p_wb_group->tx.crac_state;
        p_group_node->tx.dir_inst   = NULL;
        
        p_group_node->rx.active     = p_wb_group->rx.active;
        p_group_node->rx.crac_state = p_wb_group->rx.crac_state;
        p_group_node->rx.dir_inst   = NULL;
    }

    return CTC_E_NONE;
}

int32
_sys_usw_flexe_wb_client_mapping(uint8 lchip, sys_wb_flexe_client_t* p_wb_client, sys_flexe_client_t* p_client_node, uint8 sync)
{    
    if (sync)
    {
        p_wb_client->client_id       = p_client_node->client_id;
        p_wb_client->client_number   = p_client_node->client_number;
        p_wb_client->group_id        = p_client_node->group_id;
        p_wb_client->flexe_shim_id   = p_client_node->flexe_shim_id;
        p_wb_client->shim_chid       = p_client_node->shim_chid;
        p_wb_client->tx_xc_chid      = p_client_node->tx_xc_chid;
        p_wb_client->rx_xc_chid      = p_client_node->rx_xc_chid;
        p_wb_client->cross_client_id = p_client_node->cross_client_id;
        p_wb_client->gport           = p_client_node->gport;
        p_wb_client->mac_id          = p_client_node->mac_id;
        p_wb_client->chan_id         = p_client_node->chan_id;
        p_wb_client->cross_enable    = p_client_node->cross_enable;
        p_wb_client->aps_role        = p_client_node->aps_role;
        p_wb_client->bind_oam        = p_client_node->bind_oam;
        p_wb_client->flow_type       = p_client_node->flow_type;

        sal_memcpy(&p_wb_client->tx, &p_client_node->tx, sizeof(sys_flexe_client_dir_t));
        sal_memcpy(&p_wb_client->rx, &p_client_node->rx, sizeof(sys_flexe_client_dir_t));
    }
    else
    {
        p_client_node->client_id       = p_wb_client->client_id;
        p_client_node->client_number   = p_wb_client->client_number;
        p_client_node->group_id        = p_wb_client->group_id;
        p_client_node->flexe_shim_id   = p_wb_client->flexe_shim_id;
        p_client_node->shim_chid       = p_wb_client->shim_chid;
        p_client_node->tx_xc_chid      = p_wb_client->tx_xc_chid;
        p_client_node->rx_xc_chid      = p_wb_client->rx_xc_chid;
        p_client_node->cross_client_id = p_wb_client->cross_client_id;
        p_client_node->gport           = p_wb_client->gport;
        p_client_node->mac_id          = p_wb_client->mac_id;
        p_client_node->chan_id         = p_wb_client->chan_id;
        p_client_node->cross_enable    = p_wb_client->cross_enable;
        p_client_node->aps_role        = p_wb_client->aps_role;
        p_client_node->bind_oam        = p_wb_client->bind_oam;
        p_client_node->flow_type       = p_wb_client->flow_type;

        sal_memcpy(&p_client_node->tx, &p_wb_client->tx, sizeof(sys_flexe_client_dir_t));
        sal_memcpy(&p_client_node->rx, &p_wb_client->rx, sizeof(sys_flexe_client_dir_t));
    }

    return CTC_E_NONE;
}

int32
_sys_usw_flexe_wb_group_mem_mapping(uint8 lchip, sys_wb_flexe_group_mem_t* p_wb_group_mem, sys_flexe_group_t* p_group_node, uint8 sync)
{
    uint32 i              = 0;
    uint32 mem_size       = 0;
    uint8* p_mem          = NULL;
    uint32 phy_list_size  = 0;
    uint32 inst_list_size = 0;
    uint32 dir_inst_size  = sizeof(sys_flexe_dir_inst_t)*MCHIP_CAP(SYS_CAP_FLEXE_MAX_INST_CNT);
    uint32 cc_inst_size   = sizeof(sys_flexe_cc_inst_t)*MCHIP_CAP(SYS_CAP_FLEXE_MAX_INST_CNT);
    sys_flexe_group_t* tmp_group_node = NULL;

    if (sync)
    {
        if (0 == p_group_node->phy_cnt)
        {
            return CTC_E_NONE;
        }

        phy_list_size  = sizeof(sys_flexe_phy_t)*p_group_node->phy_cnt;
        inst_list_size = sizeof(uint8)*p_group_node->inst_cnt;

        p_wb_group_mem->group_id = p_group_node->group_id;
        sal_memcpy(p_wb_group_mem->phy_list,    p_group_node->phy_list,    phy_list_size);
        sal_memcpy(p_wb_group_mem->inst_list,   p_group_node->inst_list,   inst_list_size);
        sal_memcpy(p_wb_group_mem->tx_dir_inst, p_group_node->tx.dir_inst, dir_inst_size);
        sal_memcpy(p_wb_group_mem->rx_dir_inst, p_group_node->rx.dir_inst, dir_inst_size);
    }
    else
    {
        (void)_sys_usw_flexe_wb_group_lookup(lchip, p_wb_group_mem->group_id, &tmp_group_node);
        if (!tmp_group_node)
        {
            return CTC_E_NOT_EXIST;
        }

        if (0 == tmp_group_node->phy_cnt)
        {
            return CTC_E_NONE;
        }

        phy_list_size  = sizeof(sys_flexe_phy_t)*tmp_group_node->phy_cnt;
        inst_list_size = sizeof(uint8)*tmp_group_node->inst_cnt;
        
        mem_size += phy_list_size;                                     /* group_node->phy_list */
        mem_size += inst_list_size;                                    /* group_node->inst_list*/
        mem_size += dir_inst_size;                                     /* group_node->tx.dir_inst */
        mem_size += dir_inst_size;                                     /* group_node->rx.dir_inst */
        mem_size += cc_inst_size*MCHIP_CAP(SYS_CAP_FLEXE_MAX_CYCLE);   /* group_node->tx.cc[i].inst */
        mem_size += cc_inst_size*MCHIP_CAP(SYS_CAP_FLEXE_MAX_CYCLE);   /* group_node->rx.cc[i].inst*/

        p_mem  = (uint8*)mem_malloc(MEM_DMPS_MODULE, mem_size);
        if(NULL == p_mem)
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(p_mem, 0, mem_size);

        tmp_group_node->phy_list = (sys_flexe_phy_t*)p_mem;
        p_mem += phy_list_size;
        
        tmp_group_node->inst_list = (uint8*)p_mem;
        p_mem += inst_list_size;

        tmp_group_node->tx.dir_inst = (sys_flexe_dir_inst_t*)p_mem;
        p_mem += dir_inst_size;

        tmp_group_node->rx.dir_inst = (sys_flexe_dir_inst_t*)p_mem;
        p_mem += dir_inst_size;
        
        for (i = 0; i < MCHIP_CAP(SYS_CAP_FLEXE_MAX_CYCLE); i ++)
        {
            tmp_group_node->tx.cc[i].inst = (sys_flexe_cc_inst_t*)p_mem;
            p_mem += cc_inst_size;

            tmp_group_node->rx.cc[i].inst = (sys_flexe_cc_inst_t*)p_mem;
            p_mem += cc_inst_size;
        }

        sal_memcpy(tmp_group_node->phy_list,    p_wb_group_mem->phy_list,    phy_list_size);
        sal_memcpy(tmp_group_node->inst_list,   p_wb_group_mem->inst_list,   inst_list_size);
        sal_memcpy(tmp_group_node->tx.dir_inst, p_wb_group_mem->tx_dir_inst, dir_inst_size);
        sal_memcpy(tmp_group_node->rx.dir_inst, p_wb_group_mem->rx_dir_inst, dir_inst_size);

        if(MCHIP_FLEXE(lchip)->flexe_wb_restore_sch)
        {
            (void)MCHIP_FLEXE(lchip)->flexe_wb_restore_sch(lchip, tmp_group_node);
        }
    }

    return CTC_E_NONE;
}

int32
sys_usw_flexe_wb_init(uint8 lchip)
{
    ctc_wb_appid_t  appid;
    sal_memset(&appid, 0, sizeof(appid));

    appid.app_id = SYS_WB_APPID(lchip, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_MASTER) ;
    appid.entry_num = SYS_WB_FEATURE_MASTER_NUM;
    appid.entry_size  = sizeof(sys_wb_flexe_master_t);
    appid.rt_en = 0;
    ctc_wb_add_appid( lchip, &appid);

    appid.app_id = SYS_WB_APPID(lchip, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_GROUP) ;
    appid.entry_num = MCHIP_CAP(SYS_CAP_FLEXE_MAX_GROUP);
    appid.entry_size  = sizeof(sys_wb_flexe_group_t);
    appid.rt_en = 0;
    ctc_wb_add_appid( lchip, &appid);

    appid.app_id = SYS_WB_APPID(lchip, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_CLIENT) ;
    appid.entry_num = MCHIP_CAP(SYS_CAP_FLEXE_MAX_CLIENT)*MCHIP_CAP(SYS_CAP_FLEXE_MAX_SHIM_CNT);
    appid.entry_size  = sizeof(sys_wb_flexe_client_t);
    appid.rt_en = 0;
    ctc_wb_add_appid( lchip, &appid);

    appid.app_id = SYS_WB_APPID(lchip, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_GROUP_MEM) ;
    appid.entry_num = MCHIP_CAP(SYS_CAP_FLEXE_MAX_GROUP);
    appid.entry_size  = sizeof(sys_wb_flexe_group_mem_t);
    appid.rt_en = 0;
    ctc_wb_add_appid( lchip, &appid);
    
    return CTC_E_NONE;
}

int32
sys_usw_flexe_wb_sync(uint8 lchip, uint32 app_id)
{
    int32 ret                                        = CTC_E_NONE;
    ctc_wb_data_t wb_data                            = {0};
    sys_wb_flexe_master_t* p_wb_flexe_master         = NULL;
    sys_wb_flexe_group_t* p_wb_flexe_group           = NULL;
    sys_wb_flexe_client_t* p_wb_flexe_client         = NULL;
    sys_wb_flexe_group_mem_t* p_wb_flexe_group_mem     = NULL;
    sys_flexe_group_t* p_group_node                  = NULL;
    sys_flexe_client_t* p_client_node                = NULL;
    ctc_slistnode_t* node                            = NULL;

    CTC_WB_ALLOC_BUFFER(&wb_data.buffer);
    MAC_LOCK;
    if(!DRV_FROM_TMM(lchip))
    {
        goto done;
    }

    /* sync master */
    if (app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_FLEXE_SUBID_MASTER)
    {
        CTC_WB_INIT_DATA_T((&wb_data), sys_wb_flexe_master_t, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_MASTER);
        if (NULL == wb_data.buffer)
        {
            ret = CTC_E_NO_MEMORY;
            goto done;
        }

        p_wb_flexe_master = (sys_wb_flexe_master_t *)wb_data.buffer;

        p_wb_flexe_master->lchip = lchip;
        p_wb_flexe_master->version = SYS_WB_VERSION_FLEXE;

        CTC_ERROR_GOTO(_sys_usw_flexe_wb_master_mapping(lchip, p_wb_flexe_master, 1), ret, done);

        wb_data.valid_cnt = 1;
        CTC_ERROR_GOTO(ctc_wb_add_entry(&wb_data), ret, done);
        CTC_WB_SYNC_END_DATA(CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_MASTER);
    }

    /* sync group */
    if (app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_FLEXE_SUBID_GROUP)
    {
        CTC_WB_INIT_DATA_T((&wb_data), sys_wb_flexe_group_t, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_GROUP);
        if (NULL == wb_data.buffer)
        {
            ret = CTC_E_NO_MEMORY;
            goto done;
        }

        CTC_SLIST_LOOP(p_usw_flexe_master[lchip]->group_list, node)
        {
            p_wb_flexe_group = (sys_wb_flexe_group_t*)((uint8*)wb_data.buffer + wb_data.valid_cnt*sizeof(sys_wb_flexe_group_t));

            p_group_node = _ctc_container_of(node, sys_flexe_group_t, head);
            CTC_ERROR_GOTO(_sys_usw_flexe_wb_group_mapping(lchip, p_wb_flexe_group, p_group_node, 1), ret, done);

            wb_data.valid_cnt ++;
        }

        if (wb_data.valid_cnt > 0)
        {
            CTC_ERROR_GOTO(ctc_wb_add_entry(&wb_data), ret, done);
        }

        CTC_WB_SYNC_END_DATA(CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_GROUP);        
    }

    /* sync client */
    if (app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_FLEXE_SUBID_CLIENT)
    {
        CTC_WB_INIT_DATA_T((&wb_data), sys_wb_flexe_client_t, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_CLIENT);
        if (NULL == wb_data.buffer)
        {
            ret = CTC_E_NO_MEMORY;
            goto done;
        }

        CTC_SLIST_LOOP(p_usw_flexe_master[lchip]->client_list, node)
        {
            p_wb_flexe_client = (sys_wb_flexe_client_t*)((uint8*)wb_data.buffer + wb_data.valid_cnt*sizeof(sys_wb_flexe_client_t));
            
            p_client_node = _ctc_container_of(node, sys_flexe_client_t, head);
            CTC_ERROR_GOTO(_sys_usw_flexe_wb_client_mapping(lchip, p_wb_flexe_client, p_client_node, 1), ret, done);

            wb_data.valid_cnt ++;
        }
        
        if (wb_data.valid_cnt > 0)
        {
            CTC_ERROR_GOTO(ctc_wb_add_entry(&wb_data), ret, done);
        }

        CTC_WB_SYNC_END_DATA(CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_CLIENT);        
    }

    /* sync group mem */
    if (app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_FLEXE_SUBID_GROUP_MEM)
    {
        CTC_WB_INIT_DATA_T((&wb_data), sys_wb_flexe_group_mem_t, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_GROUP_MEM);
        if (NULL == wb_data.buffer)
        {
            ret = CTC_E_NO_MEMORY;
            goto done;
        }

        CTC_SLIST_LOOP(p_usw_flexe_master[lchip]->group_list, node)
        {
            p_wb_flexe_group_mem = (sys_wb_flexe_group_mem_t*)((uint8*)wb_data.buffer + wb_data.valid_cnt*sizeof(sys_wb_flexe_group_mem_t));

            p_group_node = _ctc_container_of(node, sys_flexe_group_t, head);
            if (0 == p_group_node->phy_cnt)
            {
                continue;
            }
            CTC_ERROR_GOTO(_sys_usw_flexe_wb_group_mem_mapping(lchip, p_wb_flexe_group_mem, p_group_node, 1), ret, done);

            wb_data.valid_cnt ++;
        }

        if (wb_data.valid_cnt > 0)
        {
            CTC_ERROR_GOTO(ctc_wb_add_entry(&wb_data), ret, done);
        }

        CTC_WB_SYNC_END_DATA(CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_GROUP_MEM);        
    }

done:

    MAC_UNLOCK;
    CTC_WB_FREE_BUFFER(wb_data.buffer);

    return ret;
}

int32
sys_usw_flexe_wb_restore(uint8 lchip)
{
    uint32 entry_cnt                                 = 0;
    int32 ret                                        = CTC_E_NONE;
    ctc_wb_query_t wb_query                          = {0};
    sys_wb_flexe_master_t   wb_flexe_master          = {0};
    sys_wb_flexe_client_t*  p_wb_flexe_client        = NULL;
    sys_wb_flexe_group_t* p_wb_flexe_group           = NULL;
    sys_wb_flexe_group_mem_t* p_wb_flexe_group_mem   = NULL;
    sys_flexe_client_t* p_flexe_client_node          = NULL;
    sys_flexe_group_t* p_flexe_group_node            = NULL;

    p_wb_flexe_group   = mem_malloc(MEM_SYSTEM_MODULE,  sizeof(sys_wb_flexe_group_t));
    p_wb_flexe_client  = mem_malloc(MEM_SYSTEM_MODULE,  sizeof(sys_wb_flexe_client_t));
    p_wb_flexe_group_mem = mem_malloc(MEM_SYSTEM_MODULE,  sizeof(sys_wb_flexe_group_mem_t));
    if ((NULL == p_wb_flexe_group_mem) || (NULL == p_wb_flexe_group) || (NULL == p_wb_flexe_client))
    {
        ret = CTC_E_NO_MEMORY;
        goto done;
    }

    CTC_WB_ALLOC_BUFFER(&wb_query.buffer);
    
    /* restore flexe master */
    CTC_WB_INIT_QUERY_T((&wb_query), sys_wb_flexe_master_t, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_MASTER);
    CTC_ERROR_GOTO(ctc_wb_query_entry(&wb_query), ret, done);
    if (wb_query.valid_cnt != 1 || wb_query.is_end != 1)
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "query flexe master error! valid_cnt: %d, is_end: %d.\n", wb_query.valid_cnt, wb_query.is_end);
        ret = CTC_E_NONE;
        goto done;
    }

    sal_memcpy((uint8*)&wb_flexe_master, (uint8*)wb_query.buffer + entry_cnt * (wb_query.key_len + wb_query.data_len), wb_query.key_len + wb_query.data_len);

    if (CTC_WB_VERSION_CHECK(SYS_WB_VERSION_FLEXE, wb_flexe_master.version))
    {
        ret = wb_flexe_master.version < CTC_WB_VERSION(5,0) ? CTC_E_NONE : CTC_E_VERSION_MISMATCH;
        goto done;
    }
    CTC_ERROR_GOTO(_sys_usw_flexe_wb_master_mapping(lchip, &wb_flexe_master, 0), ret, done);

    /* restore flexe group */
    sal_memset(p_wb_flexe_group, 0, sizeof(sys_wb_flexe_group_t));
    CTC_WB_INIT_QUERY_T((&wb_query), sys_wb_flexe_group_t, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_GROUP);
    CTC_WB_QUERY_ENTRY_BEGIN((&wb_query));
        p_flexe_group_node = mem_malloc(MEM_DMPS_MODULE, sizeof(sys_flexe_group_t));
        if (NULL == p_flexe_group_node)
        {
            ret = CTC_E_NO_MEMORY;
            goto done;
        }
        sal_memset(p_flexe_group_node, 0, sizeof(sys_flexe_group_t));
        sal_memcpy((uint8*)p_wb_flexe_group, (uint8*)(wb_query.buffer) + entry_cnt * (wb_query.key_len + wb_query.data_len), wb_query.key_len + wb_query.data_len);
        entry_cnt++;

        CTC_ERROR_GOTO(_sys_usw_flexe_wb_group_mapping(lchip, p_wb_flexe_group, p_flexe_group_node, 0), ret, done);
        ctc_slist_add_tail(p_usw_flexe_master[lchip]->group_list, &(p_flexe_group_node->head));
        
    CTC_WB_QUERY_ENTRY_END((&wb_query));
    
    /* restore flexe client */
    sal_memset(p_wb_flexe_client, 0, sizeof(sys_wb_flexe_client_t));
    CTC_WB_INIT_QUERY_T((&wb_query), sys_wb_flexe_client_t, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_CLIENT);
    CTC_WB_QUERY_ENTRY_BEGIN((&wb_query));
        p_flexe_client_node = mem_malloc(MEM_DMPS_MODULE, sizeof(sys_flexe_client_t));
        if (NULL == p_flexe_client_node)
        {
            ret = CTC_E_NO_MEMORY;
            goto done;
        }
        sal_memset(p_flexe_client_node, 0, sizeof(sys_flexe_client_t));
        sal_memcpy((uint8*)p_wb_flexe_client, (uint8*)(wb_query.buffer) + entry_cnt * (wb_query.key_len + wb_query.data_len), wb_query.key_len + wb_query.data_len);
        entry_cnt++;

        CTC_ERROR_GOTO(_sys_usw_flexe_wb_client_mapping(lchip, p_wb_flexe_client, p_flexe_client_node, 0), ret, done);
        ctc_slist_add_tail(p_usw_flexe_master[lchip]->client_list, &(p_flexe_client_node->head));
        
    CTC_WB_QUERY_ENTRY_END((&wb_query));

    /* restore group mem mgr */
    sal_memset(p_wb_flexe_group_mem, 0, sizeof(sys_wb_flexe_group_mem_t));
    CTC_WB_INIT_QUERY_T((&wb_query), sys_wb_flexe_group_mem_t, CTC_FEATURE_FLEXE, SYS_WB_APPID_FLEXE_SUBID_GROUP_MEM);
    CTC_WB_QUERY_ENTRY_BEGIN((&wb_query));
        sal_memcpy((uint8*)p_wb_flexe_group_mem, (uint8*)(wb_query.buffer) + entry_cnt * (wb_query.key_len + wb_query.data_len), wb_query.key_len + wb_query.data_len);
        entry_cnt++;

        CTC_ERROR_GOTO(_sys_usw_flexe_wb_group_mem_mapping(lchip, p_wb_flexe_group_mem, NULL, 0), ret, done);
        
    CTC_WB_QUERY_ENTRY_END((&wb_query));

done:    
    if (p_wb_flexe_group_mem)
    {
        mem_free(p_wb_flexe_group_mem);
    }

    if (p_wb_flexe_group)
    {
        mem_free(p_wb_flexe_group);
    }
    
    if (p_wb_flexe_client)
    {
        mem_free(p_wb_flexe_client);
    }
    
    CTC_WB_FREE_BUFFER(wb_query.buffer);

    return ret;
}

#define  __FLEXE_INIT__

/**
 @brief initialize the flexe module
*/
int32
sys_usw_flexe_init(uint8 lchip, void* p_cfg)
{
    uint8 i = 0;
    sys_flexe_master_t* master_ptr = NULL;    
    int32 ret = CTC_E_NONE;

    if (p_usw_flexe_master[lchip] != NULL)
    {
        return CTC_E_NONE;
    }

    /*alloc&init DB and mutex*/
    p_usw_flexe_master[lchip] = (sys_flexe_master_t*)mem_malloc(MEM_DMPS_MODULE, sizeof(sys_flexe_master_t));
    if (NULL == p_usw_flexe_master[lchip])
    {
        SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        return CTC_E_NO_MEMORY;

    }

    sal_memset(p_usw_flexe_master[lchip], 0, sizeof(sys_flexe_master_t));

    p_usw_flexe_master[lchip]->group_list = ctc_slist_new();
    if (NULL == p_usw_flexe_master[lchip]->group_list)
    {
        mem_free(p_usw_flexe_master[lchip]);
        return CTC_E_NO_MEMORY;
    }

    p_usw_flexe_master[lchip]->client_list = ctc_slist_new();
    if (NULL == p_usw_flexe_master[lchip]->client_list)
    {
        mem_free(p_usw_flexe_master[lchip]);
        return CTC_E_NO_MEMORY;
    }

    p_usw_flexe_master[lchip]->cr_timer = (sys_flexe_cr_timer_t**)mem_malloc(MEM_DMPS_MODULE, sizeof(sys_flexe_cr_timer_t*) * MCHIP_CAP(SYS_CAP_FLEXE_MAX_SHIM_CNT));
    if (NULL == p_usw_flexe_master[lchip]->cr_timer)
    {
        ret = CTC_E_NO_MEMORY;
        goto RELEASE_PTR_RETURN;
    }    
    for (i = 0; i < MCHIP_CAP(SYS_CAP_FLEXE_MAX_SHIM_CNT); i++)
    {
        p_usw_flexe_master[lchip]->cr_timer[i] = (sys_flexe_cr_timer_t*)mem_malloc(MEM_DMPS_MODULE, sizeof(sys_flexe_cr_timer_t) * MCHIP_CAP(SYS_CAP_FLEXE_MAX_INST_CNT));
        if (NULL == p_usw_flexe_master[lchip]->cr_timer[i])
        {
            ret = CTC_E_NO_MEMORY;
            goto RELEASE_PTR_RETURN;
        }        
        sal_memset(p_usw_flexe_master[lchip]->cr_timer[i], 0, sizeof(sys_flexe_cr_timer_t) *  MCHIP_CAP(SYS_CAP_FLEXE_MAX_INST_CNT));
    }

    if(MCHIP_FLEXE(lchip)->flexe_init)
    {
        CTC_ERROR_GOTO(MCHIP_FLEXE(lchip)->flexe_init(lchip, p_cfg), ret, RELEASE_PTR_RETURN);
    }

    /* register isr */
    sys_usw_interrupt_register_flexe_isr(lchip, SYS_INTR_FLEXE_SUB_TYPE_OH, sys_usw_flexe_event_isr);
    /* start monitor */
    CTC_ERROR_GOTO(sys_usw_flexe_monitor_status(lchip), ret, RELEASE_PTR_RETURN);

    CTC_ERROR_GOTO(sys_usw_wb_sync_register_cb(lchip, CTC_FEATURE_FLEXE,SYS_WB_APPID_FLEXE_SUBID_MAX, sys_usw_flexe_wb_sync), \
        ret, RELEASE_PTR_RETURN);

    /*dump db*/
    CTC_ERROR_GOTO(sys_usw_dump_db_register_cb(lchip, CTC_FEATURE_FLEXE, sys_usw_flexe_dump_db), ret, RELEASE_PTR_RETURN);

    if (CTC_WB_ENABLE(lchip) && DRV_FROM_TMM(lchip))
    {
        if(CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
        {
            CTC_ERROR_GOTO(sys_usw_flexe_wb_restore(lchip), ret, RELEASE_PTR_RETURN);
        }
        CTC_ERROR_GOTO(sys_usw_flexe_wb_init(lchip), ret, RELEASE_PTR_RETURN);
    }

    sys_usw_mchip_set_feature_en(lchip, CTC_FEATURE_FLEXE);
    
    return CTC_E_NONE;
    
RELEASE_PTR_RETURN:

    for (i = 0; i < MCHIP_CAP(SYS_CAP_FLEXE_MAX_SHIM_CNT); i++)
    {
        if (p_usw_flexe_master[lchip]->cr_timer[i])
        {
            mem_free(p_usw_flexe_master[lchip]->cr_timer[i]);
        }
    }
    if (p_usw_flexe_master[lchip]->cr_timer)
    {
        mem_free(p_usw_flexe_master[lchip]->cr_timer);
    }
    master_ptr = p_usw_flexe_master[lchip];
    mem_free(master_ptr);
    p_usw_flexe_master[lchip] = NULL;

    return ret;
}

int32 sys_usw_flexe_deinit(uint8 lchip)
{
    uint8 i = 0;
    sys_flexe_master_t* master_ptr = NULL;
    LCHIP_CHECK(lchip);

    master_ptr = p_usw_flexe_master[lchip];
    if(!master_ptr)
    {
        return CTC_E_NONE;
    }
#if 0
    if(g_flexe_dump_fp)
    {
        sal_fclose(g_flexe_dump_fp);
        g_flexe_dump_fp = NULL;
    }
#endif
    if (master_ptr->group_list)
    {
        ctc_slist_free(master_ptr->group_list);
    }
    if (master_ptr->client_list)
    {
        ctc_slist_free(master_ptr->client_list);
    }
    if(master_ptr->p_monitor_scan)
    {
        sal_task_destroy(master_ptr->p_monitor_scan);
        master_ptr->p_monitor_scan = NULL;
    }
    if(master_ptr->cr_timer_scan.monitor_task)
    {
        sal_task_destroy(master_ptr->cr_timer_scan.monitor_task);
        master_ptr->cr_timer_scan.monitor_task = NULL;
    }
    if(master_ptr->p_monitor_alarm_scan)
    {
        sal_task_destroy(master_ptr->p_monitor_alarm_scan);
        master_ptr->p_monitor_alarm_scan = NULL;
    }

    for (i = 0; i < MCHIP_CAP(SYS_CAP_FLEXE_MAX_SHIM_CNT); i++)
    {
        if (p_usw_flexe_master[lchip]->cr_timer[i])
        {
            mem_free(p_usw_flexe_master[lchip]->cr_timer[i]);
        }
    }
    if (p_usw_flexe_master[lchip]->cr_timer)
    {
        mem_free(p_usw_flexe_master[lchip]->cr_timer);
    }

    mem_free(master_ptr);
    p_usw_flexe_master[lchip] = NULL;

    return CTC_E_NONE;
}

#define __FLEX_SYS_API__
int32
sys_usw_flexe_set_en(uint8 lchip, uint16 serdes_id, uint8 enable)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    
    FLEXE_DUMP("\n\n\n*************************************************************************\n");
    FLEXE_DUMP("flexe serdes %d flexe-en %s\n", serdes_id, enable?"enable":"disable");
    FLEXE_DUMP("\n*************************************************************************\n\n");

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_set_en)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_set_en(lchip, serdes_id, enable);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_get_en(uint8 lchip, uint16 serdes_id, uint8* enable)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_en)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_en(lchip, serdes_id, enable);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_create_group(uint8 lchip, uint32 group_id, ctc_flexe_grp_t* p_group)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    /* User Param check */
    if (p_group->group_num > SYS_FLEXE_MAX_GROUP_NUM)
    {
        SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " %% [FlexE] group_number can not be bigger than 0x%x!\n", SYS_FLEXE_MAX_GROUP_NUM);
        return CTC_E_INVALID_PARAM;
    }
    if (group_id == SYS_FLEXE_UNUSED_FLAG_U32)
    {
        SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " %% [FlexE] group ID can not be 0x%x!\n", SYS_FLEXE_UNUSED_FLAG_U32);
        return CTC_E_INVALID_PARAM;
    }
    if ((0 != p_group->flag) && (CTC_FLEXE_GRP_FLAG_MANUAL != p_group->flag))
    {
        SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "%% [FlexE] Invaild switch mode value %d!\n", p_group->flag);
        return CTC_E_INVALID_PARAM;
    }

    FLEXE_DUMP("\n\n\n*************************************************************************\n");
    FLEXE_DUMP("flexe create group %u group-number %u switch-mode %s\n", group_id, \
        p_group->group_num, (CTC_FLEXE_GRP_FLAG_MANUAL == p_group->flag) ? "Manual" : "Dynamic");
    FLEXE_DUMP("\n*************************************************************************\n\n");

    MAC_LOCK;
    if (MCHIP_FLEXE(lchip)->flexe_create_group)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_create_group(lchip, group_id, p_group);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_destroy_group(uint8 lchip, uint32 group_id)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    FLEXE_DUMP("\n\n\n*************************************************************************\n");
    FLEXE_DUMP("flexe destroy group %u\n", group_id);
    FLEXE_DUMP("\n*************************************************************************\n\n");

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_destroy_group)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_destroy_group(lchip, group_id);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_get_group(uint8 lchip, uint32 group_id, ctc_flexe_grp_t* p_group)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_group)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_group(lchip, group_id, p_group);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_set_group_property(uint8 lchip, uint32 group_id, ctc_flexe_grp_prop_t group_prop, void* p_value)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    MAC_LOCK;
    switch (group_prop)
    {
    case CTC_FLEXE_GRP_PROP_GRP_NUM:
    case CTC_FLEXE_GRP_PROP_PHY:
    case CTC_FLEXE_GRP_PROP_CAL_SEL:
    case CTC_FLEXE_GRP_PROP_SWITCH_TRIGGER:
    case CTC_FLEXE_GRP_PROP_SWITCH_MODE:
    case CTC_FLEXE_GRP_PROP_CR_TIMER:
    case CTC_FLEXE_GRP_PROP_SYNC_MSG_EN:
    case CTC_FLEXE_GRP_PROP_PAD_EN:
        if(MCHIP_FLEXE(lchip)->flexe_set_group_prop)
        {
            ret = MCHIP_FLEXE(lchip)->flexe_set_group_prop(lchip, group_id, group_prop, p_value);
        }
        else
        {
            ret = CTC_E_NOT_SUPPORT;
        }
        break;
    default:
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    if (CTC_FLEXE_GRP_PROP_CAL_SEL == group_prop)
    {
        CTC_ERROR_RETURN(sys_usw_flexe_update_misc(lchip));
    }

    return ret;
}

int32
sys_usw_flexe_get_group_property(uint8 lchip, uint32 group_id, ctc_flexe_grp_prop_t group_prop, void* p_value)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_group_prop)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_group_prop(lchip, group_id, group_prop, p_value);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_add_client(uint8 lchip, uint32  client_id, ctc_flexe_client_t* p_client)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    FLEXE_DUMP("\n\n\n*************************************************************************\n");
    FLEXE_DUMP("flexe add client %d\n", client_id);
    FLEXE_DUMP("\n*************************************************************************\n\n");

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_add_client)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_add_client(lchip, client_id, p_client);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_remove_client(uint8 lchip, uint32  client_id)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    FLEXE_DUMP("\n\n\n*************************************************************************\n");
    FLEXE_DUMP("flexe remove client %d\n", client_id);
    FLEXE_DUMP("\n*************************************************************************\n\n");

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_remove_client)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_remove_client(lchip, client_id);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_get_client(uint8 lchip, uint32  client_id, ctc_flexe_client_t* p_client)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_client)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_client(lchip, client_id, p_client);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_set_client_property(uint8 lchip, uint32  client_id, uint32 client_prop, void* p_value)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    MAC_LOCK;
    switch (client_prop)
    {
    case CTC_FLEXE_CLIENT_PROP_GROUP_ID:
    case CTC_FLEXE_CLIENT_PROP_CLIENT_NUM:
    case CTC_FLEXE_CLIENT_PROP_BINDING_PORT:
    case CTC_FLEXE_CLIENT_PROP_SLOT:
    case CTC_FLEXE_CLIENT_PROP_TX_RX:
    case SYS_FLEXE_CLIENT_PROP_BIND_OAM:
    case CTC_FLEXE_CLIENT_PROP_MAC_EN:
    case CTC_FLEXE_CLIENT_PROP_RX_RECOVER:
        if(MCHIP_FLEXE(lchip)->flexe_set_client_prop)
        {
            ret = MCHIP_FLEXE(lchip)->flexe_set_client_prop(lchip, client_id, client_prop, p_value);
        }
        else
        {
            ret = CTC_E_NOT_SUPPORT;
        }
        break;
    default:
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_get_client_property(uint8 lchip, uint32  client_id, uint32 client_prop, void* p_value)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    SYS_FLEXE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_client_prop)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_client_prop(lchip, client_id, client_prop, p_value);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_get_client_link_up(uint8 lchip, uint32  client_id, bool* p_is_up)
{
    int32 ret = 0;
    uint8 is_up = FALSE;

    SYS_FLEXE_INIT_CHECK();

    *p_is_up = (bool)FALSE;
    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_client_link_up)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_client_link_up(lchip, client_id, &is_up);
        *p_is_up = (bool)is_up;
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_set_client_cross(uint8 lchip, ctc_flexe_cross_t* p_cross)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_set_client_cross)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_set_client_cross(lchip, p_cross);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_get_client_cross(uint8 lchip, ctc_flexe_cross_t* p_cross)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_client_cross)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_client_cross(lchip, p_cross);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_set_phy_property(uint8 lchip, uint16 serdes_id, ctc_flexe_phy_prop_t phy_prop, void* p_value)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_set_phy_prop)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_set_phy_prop(lchip, serdes_id, phy_prop, p_value);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_get_phy_property(uint8 lchip, uint16 serdes_id, ctc_flexe_phy_prop_t phy_prop, void* p_value)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_phy_prop)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_phy_prop(lchip, serdes_id, phy_prop, p_value);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_get_phy_inst_id(uint8 lchip, uint8 dp_id, uint8 asic_inst_id, uint8* p_serdes_id, uint32* p_instance_id)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_phy_inst_id)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_phy_inst_id(lchip, dp_id, asic_inst_id, p_serdes_id, p_instance_id);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_get_phy_oh_sync(uint8 lchip, uint8 serdes_id, uint32* p_enable)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();
    if(MCHIP_FLEXE(lchip)->flexe_get_phy_oh_sync)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_phy_oh_sync(lchip, serdes_id, p_enable);
    }
    else return CTC_E_NOT_SUPPORT;

    return ret;
}

int32
sys_usw_flexe_get_dp_asic_id(uint8 lchip, uint8 serdes_id, uint32 instance_id, uint8* p_dp_id, uint8 p_asic_inst_id[])
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_get_dp_asic_id)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_get_dp_asic_id(lchip, serdes_id, instance_id, p_dp_id, p_asic_inst_id);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_debug_show_ins_sch(uint8 lchip, uint8 flexe_shim_id, uint8 inst_id, uint8 dir)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_debug_show_ins_sch)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_debug_show_ins_sch(lchip, flexe_shim_id, inst_id, dir);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_debug_show_inst_status(uint8 lchip, uint8 flexe_shim_id)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_debug_show_inst_status)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_debug_show_inst_status(lchip, flexe_shim_id);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_debug_show_inst_ohram(uint8 lchip, uint8 flexe_shim_id, uint8 inst_id, uint8 dir)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_debug_show_inst_ohram)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_debug_show_inst_ohram(lchip, flexe_shim_id, inst_id, dir);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_debug_show_client(uint8 lchip, uint32 client_id)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_debug_show_client)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_debug_show_client(lchip, client_id);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_debug_show_group(uint8 lchip, uint32 group_id)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_debug_show_group)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_debug_show_group(lchip, group_id);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_debug_show_status(uint8 lchip)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_debug_show_status)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_debug_show_status(lchip);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

int32
sys_usw_flexe_debug_show_alarm(uint8 lchip)
{
    int32 ret = 0;
    SYS_FLEXE_INIT_CHECK();

    MAC_LOCK;
    if(MCHIP_FLEXE(lchip)->flexe_debug_show_alarm)
    {
        ret = MCHIP_FLEXE(lchip)->flexe_debug_show_alarm(lchip);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }
    MAC_UNLOCK;

    return ret;
}

